using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Web.UI;
using System.Web.UI.Adapters;
using System.Web.UI.WebControls.WebParts;

using SPWebPartManager = Microsoft.SharePoint.WebPartPages.SPWebPartManager;

namespace Aks.Web.UI.WebControls.WebParts.Adapters
{
	/// <summary>
	/// Control adapter for the <see cref="WebPartZone"/> class.
	/// </summary>
	/// <remarks>
	///		Change History
	///		<list type="table">
	///			<listheader>
	///				<term>Version</term>
	///				<description>Description</description>
	///			</listheader>
	///			<item>
	///				<term>0.1</term>
	///				<description>Original version from HiSoftware AKS 2.0, designed by Robert B Yonaitis</description>
	///			</item>
	///			<item>
	///				<term>0.2</term>
	///				<description>Code cleanup</description>
	///			</item>
	///		</list>
	/// </remarks>
	public class WebPartZoneAdapter : ControlAdapter
	{
		#region | Methods [Public] |

		/// <summary>
		/// Generates the target-specific markup for the control to which the control adapter is attached.
		/// </summary>
		/// <param name="writer">The <see cref="HtmlTextWriter"/> to use to render the target-specific output.</param>
		protected override void Render(HtmlTextWriter writer)
		{
			// if not edit mode, change each table to a div; otherwise, add summary to each table
			if (!IsEditMode(Page))
			{
				var zone = Control as WebPartZone;
				RenderWithDiv(writer, zone);
			}
			else
			{
				// get html from original control
				var builder = new StringBuilder();
				using (var baseWriter = new HtmlTextWriter(new StringWriter(builder, CultureInfo.InvariantCulture)))
				{
					base.Render(baseWriter);
				}

				// render base html with summary attribute added to the zone title table
				writer.Write(AddZoneTitleSummary(builder.ToString()));
			}
		}

		#endregion


		#region | Methods [Private] |

		/// <summary>
		/// Determines whether the page is in edit mode.
		/// </summary>
		/// <param name="page">The current page.</param>
		/// <returns></returns>
		private static bool IsEditMode(Page page)
		{
			if (page == null)
			{
				return false;
			}
			var manager = WebPartManager.GetCurrentWebPartManager(page) as SPWebPartManager;
			return (manager != null && manager.GetDisplayMode().AllowPageDesign);
		}


		/// <summary>
		/// Renders the specified <paramref name="zone"/> with a div, instead of the standard table.
		/// </summary>
		/// <param name="writer">The <see cref="HtmlTextWriter"/> to use to render the specific output.</param>
		/// <param name="zone">The <see cref="WebPartZone"/> to render contents for.</param>
		private static void RenderWithDiv(HtmlTextWriter writer, WebPartZoneBase zone)
		{
			// render zone begin tag
			writer.AddAttribute(HtmlTextWriterAttribute.Id, zone.ID);
			if (!String.IsNullOrEmpty(zone.CssClass))
			{
				writer.AddAttribute(HtmlTextWriterAttribute.Class, zone.CssClass);
			}
			writer.AddAttribute(HtmlTextWriterAttribute.Class, "AspNet-WebPartZone-" + zone.LayoutOrientation);
			writer.RenderBeginTag(HtmlTextWriterTag.Div);

			// render web parts within a div
			for (int i = 0; i < zone.WebParts.Count; i++)
			{
				writer.AddAttribute(HtmlTextWriterAttribute.Class, "AspNet-WebPart");
				writer.RenderBeginTag(HtmlTextWriterTag.Div);
				zone.WebParts[i].RenderControl(writer);
				writer.RenderEndTag();
			}

			// render zone end tag
			writer.RenderEndTag();
		}


		/// <summary>
		/// Adds a summary attribute to the HTML table tag
		/// </summary>
		/// <param name="html">Original HTML.</param>
		/// <returns>Original HTML with a table summary attribute for the web part zone title.</returns>
		private static string AddZoneTitleSummary(string html)
		{
			/**
			 * A standard web part zone typically renders the following HTML:
			 *     <table cellpadding="1" cellspacing="0" border="0" style="width:100%;"><tr><td align="center" class="ms-SPZoneLabel"><nobr>Header</nobr></td>
			 * This method adds a summary attribute to the <table> element.
			 */

			// init vars
			const string tableTag = "<table";
			const string tableSummaryFormat = @" summary=""This webpart zone represents the {0} area.""";
			const string titlePrefix = @"class=""ms-SPZoneLabel""><nobr>";  // html directly before the name of the zone

			// get index of zone label
			int zoneTitlePrefixIndex = html.IndexOf(titlePrefix, StringComparison.OrdinalIgnoreCase);

			// if zone label exists, ...
			if (zoneTitlePrefixIndex > 0)
			{
				// init vars
				string zoneTitle = "";

				// find the starting position of the actual zone title
				int zoneTitleIndex = zoneTitlePrefixIndex + titlePrefix.Length;

				// loop thru characters to read the title
				while (html[zoneTitleIndex] != '<')
				{
					zoneTitle += html[zoneTitleIndex];
					zoneTitleIndex++;
				}

				// find the position of the zone title's table tag
				int zoneTitleTableIndex = html.Substring(0, zoneTitleIndex).LastIndexOf(tableTag, StringComparison.OrdinalIgnoreCase);
				if (zoneTitleTableIndex >= 0)
				{
					// append the length of the searched-for string to find the first position after it (i.e. "<table| ...")
					zoneTitleTableIndex += tableTag.Length;

					// insert a table summary
					html = html.Insert(zoneTitleTableIndex, String.Format(CultureInfo.CurrentCulture, tableSummaryFormat, zoneTitle));
				}
			}

			// return
			return html;
		}

		#endregion
	}
}
